package space

import (
	"container/list"
	"errors"
	"math"
	"src/zeus/common"
	"src/zeus/iserver"
	"src/zeus/linmath"

	"src/zeus/logger"
)

/*
整个九宫格计算体系用的是厘米
客户端与服务器的navmush用的都是米

*/

// 目前先写死了，支持两种类型的可视距离
const (
	TilesTypeCount = 1
)

// 目前游戏里使用的是米，但坐标系统使用的是厘米。
var TilesSizeList = []int{2000}

// TileCoord 基于九官格的坐标系统
type TileCoord struct {
	TilesList [TilesTypeCount]*Tiles
	AnchorPos linmath.Vector3
}

// NewTileCoord  创建新的坐标系统
func NewTileCoord(width, height, size int) *TileCoord {
	tilecoord := &TileCoord{}
	// for i := 0; i < TilesTypeCount; i++ {
	tilecoord.TilesList[0] = newTiles(width, height, size, uint8(0))
	// }
	return tilecoord
}

func (c *TileCoord) SetAnchor(pos linmath.Vector3) {
	c.AnchorPos = pos
	for i := 0; i < TilesTypeCount; i++ {
		c.TilesList[i].AnchorPos = pos
	}
}

// 更新对象的可见性，刷新一下
func (c *TileCoord) RefreshShow(n iserver.ICoordEntity) {
	if n.GetHide() {
		return
	}
	if !n.IsAOIReady() {
		return
	}
	if n.GetAOILayerIndex() >= uint8(len(c.TilesList)) {
		return
	}
	if n.IsAOITrigger() {
		for _, v := range c.TilesList {
			// v.update(n)
			v.refreshShow(n)

		}
	} else {
		// c.TilesList[n.GetAOILayerIndex()].update(n)
		c.TilesList[n.GetAOILayerIndex()].refreshShow(n)
	}
}

// UpdateCoord 更新坐标位置
func (c *TileCoord) UpdateCoord(n iserver.ICoordEntity) {
	if n.GetHide() {
		return
	}
	if !n.IsAOIReady() {
		return
	}
	if n.GetAOILayerIndex() >= uint8(len(c.TilesList)) {
		return
	}
	if n.IsAOITrigger() {
		for _, v := range c.TilesList {
			v.update(n)
		}
	} else {
		c.TilesList[n.GetAOILayerIndex()].update(n)
	}
}

// RemoveFromCoord 从坐标系统中删除
func (c *TileCoord) RemoveFromCoord(n iserver.ICoordEntity) {
	if n.IsAOITrigger() {
		for _, v := range c.TilesList {
			v.remove(n)
		}
	} else {
		c.TilesList[n.GetAOILayerIndex()].remove(n)
	}
}

// ChangeAOIIndex 改变在坐标系统中的层级
func (c *TileCoord) ChangeAOIIndex(n iserver.ICoordEntity, newIndex uint8) {
	if n.GetAOILayerIndex() == newIndex {
		return
	}
	c.RemoveFromCoord(n)
	n.SetAOILayerIndex(newIndex)
	c.UpdateCoord(n)
}

// TravsalAOI 遍AOI范围内的对象
func (c *TileCoord) TravsalAOI(n iserver.ICoordEntity, cb func(iserver.ICoordEntity) bool) {
	if n.IsAOITrigger() {
		for _, v := range c.TilesList {
			if v.TravsalAOI(n, cb) {
				return
			}
		}
	} else {
		c.TilesList[n.GetAOILayerIndex()].TravsalAOI(n, cb)
	}
}

// TravsalAOI 遍AOI范围内的对象
func (c *TileCoord) TravsalAOINoCheck(n iserver.ICoordEntity, cb func(iserver.ICoordEntity) bool) {
	if n.IsAOITrigger() {
		for _, v := range c.TilesList {
			if v.TravsalAOINoCheck(n, cb) {
				return
			}
		}
	} else {
		c.TilesList[n.GetAOILayerIndex()].TravsalAOINoCheck(n, cb)
	}
}

func (c *TileCoord) GetTileIndexByRadius(radius int) int {
	index := 0
	var i int = 0
	for i = 0; i < len(c.TilesList); i++ {
		if c.TilesList[i].dist <= radius {
			if i > 0 {
				index = i - 1
			}
			break
		}
	}
	if i == len(c.TilesList) {
		index = len(c.TilesList) - 1
	}
	return index
}

// func GetTileIndexByRadius(radius int) int {
// 	index := 0
// 	var i int = 0
// 	for i = 0; i < len(TilesSizeList); i++ {
// 		if TilesSizeList[i] <= radius {
// 			if i > 0 {
// 				index = i - 1
// 			}
// 			break
// 		}
// 	}
// 	if i == len(TilesSizeList) {
// 		index = len(TilesSizeList) - 1
// 	}
// 	return index
// }

// 遍历center为中心，半径范围radius内的所有实体执行cb
func (c *TileCoord) TravsalRange(center *linmath.Vector3, radius int, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalRange(center, radius, cb, false)
}

// 遍历center为中心，半径范围radius,角度为angle,朝向为rota的扇形内所有实体执行cb
func (c *TileCoord) TravsalSector(center *linmath.Vector3, radius int, rota int32, angle int32, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalSector(center, radius, rota, angle, cb, false)
}

// 遍历center为中心，长宽为 length,width,朝向为rota的矩形内所有实体执行cb
func (c *TileCoord) TravsalSquare(center *linmath.Vector3, length, width int, rota int32, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(length)].TravsalSquare(center, length, width, rota, cb, false)
}
func (c *TileCoord) TravsalRangeNocheckModelRadius(center *linmath.Vector3, radius int, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalRange(center, radius, cb, true)
}

// 遍历center为中心，半径范围radius,角度为angle,朝向为rota的扇形内所有实体执行cb
func (c *TileCoord) TravsalSectorNocheckModelRadius(center *linmath.Vector3, radius int, rota int32, angle int32, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalSector(center, radius, rota, angle, cb, true)
}

// 遍历center为中心，长宽为 length,width,朝向为rota的矩形内所有实体执行cb
func (c *TileCoord) TravsalSquareNocheckModelRadius(center *linmath.Vector3, length, width int, rota int32, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(length)].TravsalSquare(center, length, width, rota, cb, true)
}

// 遍历center所在的Tower，在该Tower内的center为中心，半径范围radius内的所有实体执行cb
func (c *TileCoord) TravsalCenter(center *linmath.Vector3, radius int, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalCenter(center, radius, cb)
}

// 遍历center为中心，已radius为半径的圆去掉已innerRadius为圆的面积
func (c *TileCoord) TravsalRing(center *linmath.Vector3, radius, innerradius int, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalRing(center, radius, innerradius, cb)

}

// 遍历center为中心，已radius为半径的圆去掉已innerRadius为圆的面积，选取朝向rota，角度为angle的扇环面积
func (c *TileCoord) TravsalSectorRing(center *linmath.Vector3, radius, innerradius int, rota, angle int32, cb func(iserver.ICoordEntity) bool) {
	c.TilesList[c.GetTileIndexByRadius(radius)].TravsalSectorRing(center, radius, innerradius, rota, angle, cb)

}

func (c *TileCoord) GetTowerIDInRect(rect *common.Rect) []int {
	radius := 0
	radiusX := rect.MaxX - rect.MinX
	radiusY := rect.MaxY - rect.MinY
	if radiusX > radiusY {
		radius = radiusX
	} else {
		radius = radiusY
	}
	return c.TilesList[c.GetTileIndexByRadius(radius)].GetTowerIDInRect(rect)
}

func (c *TileCoord) TraversalByTowerID(rect *common.Rect, towerIDs []int, cb func(iserver.ICoordEntity) bool) {
	radius := 0
	radiusX := rect.MaxX - rect.MinX
	radiusY := rect.MaxY - rect.MinY
	if radiusX > radiusY {
		radius = radiusX
	} else {
		radius = radiusY
	}
	c.TilesList[c.GetTileIndexByRadius(radius)].TraversalByIDList(rect, towerIDs, cb)
}

////////////////////////////////////////////////////////////////

// CoordPos Coord系统使用的位置
type CoordPos struct {
	X int
	Y int
}

func newCoordPos(pos, anchor linmath.Vector3) CoordPos {

	return CoordPos{
		X: int((pos.X)*100 - anchor.X),
		Y: int((pos.Z)*100 - anchor.Z),
	}
}

//////////////////////////////////////////////////////////////

const (
	towerDir_All       = 0
	towerDir_Left      = 1
	towerDir_LeftDown  = 2
	towerDir_Down      = 3
	towerDir_RightDown = 4
	towerDir_Right     = 5
	towerDir_RightUp   = 6
	towerDir_Up        = 7
	towerDir_LeftUp    = 8
)

// Tower 灯塔
type Tower struct {
	tiles *Tiles

	gridX int
	gridY int

	neighbours []int

	aoiEntities *list.List
	entities    *list.List
}

func newTower(tiles *Tiles, gridX, gridY int) *Tower {

	t := new(Tower)
	t.tiles = tiles
	t.gridX = gridX
	t.gridY = gridY
	t.entities = list.New()
	t.aoiEntities = list.New()

	t.init()

	return t
}

func (t *Tower) init() {
	t.neighbours = make([]int, 9)

	t.neighbours[towerDir_All] = t.getNeighbourID(0, 0)
	t.neighbours[towerDir_Left] = t.getNeighbourID(-1, 0)
	t.neighbours[towerDir_LeftDown] = t.getNeighbourID(-1, -1)
	t.neighbours[towerDir_Down] = t.getNeighbourID(0, -1)
	t.neighbours[towerDir_RightDown] = t.getNeighbourID(1, -1)
	t.neighbours[towerDir_Right] = t.getNeighbourID(1, 0)
	t.neighbours[towerDir_RightUp] = t.getNeighbourID(1, 1)
	t.neighbours[towerDir_Up] = t.getNeighbourID(0, 1)
	t.neighbours[towerDir_LeftUp] = t.getNeighbourID(-1, 1)
}

func (t *Tower) getNeighbourID(deltaX, deltaY int) int {
	return t.tiles.getTowerID(t.gridX+deltaX, t.gridY+deltaY)
}

func (t *Tower) add(n iserver.ICoordEntity) {
	t.notifyTowerAdd(n)
	t.travsalNeighour(towerDir_All, func(tt *Tower) bool {
		tt.notifyTowerAdd(n)
		return false
	})

	t.addToList(n)
}

func (t *Tower) addToList(n iserver.ICoordEntity) {
	if n.IsAOITrigger() {
		t.aoiEntities.PushFront(n)
	} else {
		t.entities.PushFront(n)
	}
}

func (t *Tower) remove(n iserver.ICoordEntity) {
	t.removeFromList(n)

	t.notifyTowerRemove(n)
	t.travsalNeighour(towerDir_All, func(tt *Tower) bool {
		tt.notifyTowerRemove(n)
		return false
	})
}

func (t *Tower) removeFromList(n iserver.ICoordEntity) {

	if n.IsAOITrigger() {
		for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
			if e.Value.(iserver.ICoordEntity).GetID() == n.GetID() {
				t.aoiEntities.Remove(e)
				break
			}
		}
	} else {
		for e := t.entities.Front(); e != nil; e = e.Next() {
			if e.Value.(iserver.ICoordEntity).GetID() == n.GetID() {
				t.entities.Remove(e)
				break
			}
		}
	}
}

func (t *Tower) moveTo(n iserver.ICoordEntity, nt *Tower) {

	deltaX := nt.gridX - t.gridX
	deltaY := nt.gridY - t.gridY

	if deltaX == 0 && deltaY == 0 {
		return
	}

	if deltaX > 1 || deltaX < -1 || deltaY > 1 || deltaY < -1 {
		t.remove(n)
		nt.add(n)
		return
	}

	t.removeFromList(n)
	t.travsalNeighour(t.getInvertDir(t.getDir(deltaX, deltaY)), func(tt *Tower) bool {
		tt.notifyTowerRemove(n)
		return false
	})

	nt.travsalNeighour(t.getDir(deltaX, deltaY), func(tt *Tower) bool {
		tt.notifyTowerAdd(n)
		return false
	})
	nt.addToList(n)
}

func (t *Tower) getDir(deltaX, deltaY int) int {

	var dir int

	if deltaX == 1 && deltaY == 0 {
		dir = towerDir_Right
	} else if deltaX == 1 && deltaY == -1 {
		dir = towerDir_RightDown
	} else if deltaX == 0 && deltaY == -1 {
		dir = towerDir_Down
	} else if deltaX == -1 && deltaY == -1 {
		dir = towerDir_LeftDown
	} else if deltaX == -1 && deltaY == 0 {
		dir = towerDir_Left
	} else if deltaX == -1 && deltaY == 1 {
		dir = towerDir_LeftUp
	} else if deltaX == 0 && deltaY == 1 {
		dir = towerDir_Up
	} else if deltaX == 1 && deltaY == 1 {
		dir = towerDir_RightUp
	}

	return dir
}

func (t *Tower) getInvertDir(dir int) int {

	var invDir int

	switch dir {
	case towerDir_Left:
		invDir = towerDir_Right
	case towerDir_LeftDown:
		invDir = towerDir_RightUp
	case towerDir_Down:
		invDir = towerDir_Up
	case towerDir_RightDown:
		invDir = towerDir_LeftUp
	case towerDir_Right:
		invDir = towerDir_Left
	case towerDir_RightUp:
		invDir = towerDir_LeftDown
	case towerDir_Up:
		invDir = towerDir_Down
	case towerDir_LeftUp:
		invDir = towerDir_RightDown
	}

	return invDir
}

func (t *Tower) travsalNeighour(dir int, cb func(*Tower) bool) bool {
	return t.tiles.travsalNeighour(t, dir, cb)
}

func (t *Tower) notifyTowerAdd(n iserver.ICoordEntity) {

	if !n.IsAOITrigger() {

		for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
			if ii, ok := e.Value.(iserver.IAOITriggerEntity); ok {
				ii.OnEntityEnterAOI(n)
			}
		}

	} else {
		if n.GetAOILayerIndex() == t.tiles.index {

			for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
				if ii, ok := e.Value.(iserver.IAOITriggerEntity); ok {
					ii.OnEntityEnterAOI(n)
				}
			}
		}

		//如果这个对象需要有触发，才会需要运行下面的逻辑
		in, ok := n.(iserver.IAOITriggerEntity)
		if !ok {
			//上层设置了需要触发，但又没有实现对应的接口
			logger.Debug(logger.LogKey_AOI, "Tower notifyTowerAdd n is not IAOITriggerEntity")
			return
		}

		for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
			ii := e.Value.(iserver.ICoordEntity)
			if ii.GetAOILayerIndex() == t.tiles.index {
				in.OnEntityEnterAOI(ii)
			}
		}

		for e := t.entities.Front(); e != nil; e = e.Next() {
			ii := e.Value.(iserver.ICoordEntity)
			in.OnEntityEnterAOI(ii)
		}
	}
}

func (t *Tower) notifyTowerRemove(n iserver.ICoordEntity) {

	if !n.IsAOITrigger() {

		for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
			if ii, ok := e.Value.(iserver.IAOITriggerEntity); ok {
				ii.OnEntityLeaveAOI(n)
			}
		}

	} else {

		if n.GetAOILayerIndex() == t.tiles.index {
			for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
				if ii, ok := e.Value.(iserver.IAOITriggerEntity); ok {
					ii.OnEntityLeaveAOI(n)
				}
			}
		}

		in, ok := n.(iserver.IAOITriggerEntity)
		if !ok {
			return
		}

		for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
			ii := e.Value.(iserver.ICoordEntity)
			if ii.GetAOILayerIndex() == t.tiles.index {
				in.OnEntityLeaveAOI(ii)
			}
		}

		for e := t.entities.Front(); e != nil; e = e.Next() {
			ii := e.Value.(iserver.ICoordEntity)
			in.OnEntityLeaveAOI(ii)
		}
	}
}

// TravsalAOI 遍历AOI对象
func (t *Tower) TravsalAOI(cb func(iserver.ICoordEntity) bool) bool {

	for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
		ii := e.Value.(iserver.ICoordEntity)
		/*
		   这里的t.tiles.index，是用来分不同大小的格子用的
		   不是用来做AOI层用的
		   所以这里把这个先去掉，等后面定义好了再修改
		*/
		// if ii.IsAOITrigger() {
		if ii.GetAOILayerIndex() == t.tiles.index && ii.IsAOITrigger() {
			if cb(ii) {
				return true
			}
		}
	}
	// 原函数是没有下面内容，这样遍历的时候会漏掉 IsAOITrigger == false的部分，觉得这里也是需要被遍历执行的
	// 因为是TravsalAOI，所以这里是否可以不遍历呢？这个要看调用这个接口的需求，是要遍历所有的 IsAOITrigger == true的实体，
	// 还是说tower里所有的实体都要被遍历到？ 感觉是前者，所以，这里可以先注释，后面根据需求来进行优化  --- add by zgb 2019.12.19
	// for e := t.entities.Front(); e != nil; e = e.Next() {
	// 	ii := e.Value.(iserver.ICoordEntity)
	// 	if cb(ii) {
	// 		return true
	// 	}
	// }
	return false
}

// TravsalAOI 遍历AOI对象,不做层级和trigger检测
func (t *Tower) TravsalAOINoCheck(cb func(iserver.ICoordEntity) bool) bool {

	for e := t.aoiEntities.Front(); e != nil; e = e.Next() {
		ii := e.Value.(iserver.ICoordEntity)
		if cb(ii) {
			return true
		}
	}
	for e := t.entities.Front(); e != nil; e = e.Next() {
		ii := e.Value.(iserver.ICoordEntity)
		if cb(ii) {
			return true
		}
	}
	return false
}

////////////////////////////////////////////////////////////////

// CoordInfo 坐标结节
type CoordInfo struct {
	entity iserver.ICoordEntity
	tower  *Tower
}

////////////////////////////////////////////////////////////////

// Tiles 九宫格系统
type Tiles struct {
	width         int
	height        int
	gridSize      int
	gridWidthNum  int
	gridHeightNum int
	dist          int
	index         uint8

	towers  []*Tower
	entites map[uint64]*CoordInfo

	towerNeighbours [][]int
	AnchorPos       linmath.Vector3
}

// dist是可视距离
func newTiles(width, height, size int, index uint8) *Tiles {

	ts := new(Tiles)
	ts.width = width
	ts.height = height
	ts.index = index

	ts.dist = size

	ts.init()
	return ts
}

func (t *Tiles) init() {
	t.gridSize = t.dist
	t.gridWidthNum = t.width/t.gridSize + 1
	t.gridHeightNum = t.height/t.gridSize + 1
	t.towers = make([]*Tower, t.gridWidthNum*t.gridHeightNum)

	t.entites = make(map[uint64]*CoordInfo)

	t.initNeighbour()
}

func (t *Tiles) initNeighbour() {

	t.towerNeighbours = make([][]int, 9)
	t.towerNeighbours[towerDir_All] = []int{towerDir_Left, towerDir_LeftDown, towerDir_Down, towerDir_RightDown, towerDir_Right, towerDir_RightUp, towerDir_Up, towerDir_LeftUp}
	t.towerNeighbours[towerDir_Left] = []int{towerDir_LeftUp, towerDir_Left, towerDir_LeftDown}
	t.towerNeighbours[towerDir_LeftDown] = []int{towerDir_LeftUp, towerDir_Left, towerDir_LeftDown, towerDir_Down, towerDir_RightDown}
	t.towerNeighbours[towerDir_Down] = []int{towerDir_LeftDown, towerDir_Down, towerDir_RightDown}
	t.towerNeighbours[towerDir_RightDown] = []int{towerDir_LeftDown, towerDir_Down, towerDir_RightDown, towerDir_Right, towerDir_RightUp}
	t.towerNeighbours[towerDir_Right] = []int{towerDir_RightDown, towerDir_Right, towerDir_RightUp}
	t.towerNeighbours[towerDir_RightUp] = []int{towerDir_RightDown, towerDir_Right, towerDir_RightUp, towerDir_Up, towerDir_LeftUp}
	t.towerNeighbours[towerDir_Up] = []int{towerDir_RightUp, towerDir_Up, towerDir_LeftUp}
	t.towerNeighbours[towerDir_LeftUp] = []int{towerDir_RightUp, towerDir_Up, towerDir_LeftUp, towerDir_Left, towerDir_LeftDown}

}

func (t *Tiles) refreshShow(n iserver.ICoordEntity) {
	// t.update(n)
	pos := newCoordPos(n.GetPos(), t.AnchorPos)
	tower := t.getTower(pos)
	if tower == nil {
		logger.Error("refreshShow failed ", pos, n.GetID())
		return
		// panic("inner wrong ")
	}
	tower.notifyTowerAdd(n)
	tower.travsalNeighour(towerDir_All, func(tt *Tower) bool {
		tt.notifyTowerAdd(n)
		return false
	})

}

// Update 更新位置
func (t *Tiles) update(n iserver.ICoordEntity) {
	pos := newCoordPos(n.GetPos(), t.AnchorPos)
	// logger.Debugf(logger.LogKey_AOI, "n.pos %v pos.X=%d pos.Y=%d", n.GetPos().Vector3, pos.X, pos.Y)
	if !t.isValidPos(pos) {
		logger.Warn("無效點位：", pos, "实体：", n)
		t.remove(n)
		return
	}

	info, ok := t.entites[n.GetID()]
	if !ok {
		if !n.GetNeedHide() {
			t.add(n, pos)
		}
	} else {
		if n.GetNeedHide() {
			t.remove(n)
			n.SetHide(true)
		}
		t.move(info, pos)
	}
}

// Remove 从坐标系统中删除
func (t *Tiles) remove(n iserver.ICoordEntity) {

	info, ok := t.entites[n.GetID()]
	if !ok {
		return
	}
	delete(t.entites, n.GetID())
	info.tower.remove(n)
}

func (t *Tiles) add(n iserver.ICoordEntity, pos CoordPos) {

	tower := t.getTower(pos)
	if tower == nil {
		logger.Error("add failed ", pos, n.GetID())
		return
		// panic("inner wrong ")
	}

	t.entites[n.GetID()] = &CoordInfo{n, tower}
	tower.add(n)
}

func (t *Tiles) move(info *CoordInfo, pos CoordPos) {

	nt := t.getTower(pos)
	if info.tower == nt || nt == nil {
		return
	}

	info.tower.moveTo(info.entity, nt)
	info.tower = nt
}

func (t *Tiles) getTower(pos CoordPos) *Tower {

	gridX := pos.X / t.gridSize
	gridY := pos.Y / t.gridSize

	id := t.getTowerID(gridX, gridY)
	tower, err := t.getTowerByID(id)
	if err != nil {
		logger.Error("invalid pos ", pos)
		return nil
		// panic("inner wrong")
	}

	if tower == nil {
		tower = newTower(t, gridX, gridY)
		t.towers[id] = tower
	}

	return tower
}

func (t *Tiles) getTowerID(gridX, gridY int) int {

	if gridX < 0 || gridX > t.gridWidthNum || gridY < 0 || gridY > t.gridHeightNum {
		// logger.Debugf(logger.LogKey_AOI, "Tiles.getTowerID gridX %d gridY %d", gridX, gridY)
		return -1
	}

	return gridY*t.gridWidthNum + gridX
}

var errInvalidIndex = errors.New("invalid index")

func (t *Tiles) getTowerByID(id int) (*Tower, error) {
	if id >= len(t.towers) || id < 0 {
		return nil, errInvalidIndex
	}
	return t.towers[id], nil
}

func (t *Tiles) getTowerByPos(gridX, gridY int) (*Tower, error) {
	id := gridY*t.gridWidthNum + gridX
	return t.getTowerByID(id)
}

func (t *Tiles) isValidPos(pos CoordPos) bool {
	if pos.X < 0 || pos.X > t.width {
		return false
	}

	if pos.Y < 0 || pos.Y > t.height {
		return false
	}

	return true
}

func (t *Tiles) travsalNeighour(tc *Tower, dir int, cb func(*Tower) bool) bool {
	for _, v := range t.towerNeighbours[dir] {
		tn, err := t.getTowerByID(tc.neighbours[v])
		if err == nil && tn != nil {
			if cb(tn) {
				return true
			}
		}
	}
	return false
}

// TravsalAOI 遍历AOI范围内的entity
func (t *Tiles) TravsalAOI(n iserver.ICoordEntity, cb func(iserver.ICoordEntity) bool) bool {
	pos := newCoordPos(n.GetPos(), t.AnchorPos)
	tt := t.getTower(pos)
	if tt == nil {
		return false
	}

	if tt.TravsalAOI(cb) {
		return true
	}
	return t.travsalNeighour(tt, towerDir_All, func(nt *Tower) bool { return nt.TravsalAOI(cb) })
}

// 遍历AOI范围内的 所有单位
func (t *Tiles) TravsalAOINoCheck(n iserver.ICoordEntity, cb func(iserver.ICoordEntity) bool) bool {
	pos := newCoordPos(n.GetPos(), t.AnchorPos)
	tt := t.getTower(pos)
	if tt == nil {
		return false
	}

	if tt.TravsalAOINoCheck(cb) {
		return true
	}
	return t.travsalNeighour(tt, towerDir_All, func(nt *Tower) bool { return nt.TravsalAOINoCheck(cb) })
}

// 遍历center为中心，半径范围radius内的所有实体执行cb
func (t *Tiles) TravsalRange(center *linmath.Vector3, radius int, cb func(iserver.ICoordEntity) bool, IsNotCheckTargetRadius bool) {
	ncenter := center.Mul(100)
	rawCenter := ncenter.Sub(t.AnchorPos)
	// rawCenter.X = rawCenter.X - t.AnchorPos.X
	// rawCenter.Z = rawCenter.Z - t.AnchorPos.Z

	minX := int(rawCenter.X) - radius
	minZ := int(rawCenter.Z) - radius
	maxX := int(rawCenter.X) + radius
	maxZ := int(rawCenter.Z) + radius

	if minX < 0 {
		minX = 0
	}
	if minZ < 0 {
		minZ = 0
	}
	if maxX > t.width {
		maxX = t.width
	}
	if maxZ > t.height {
		maxZ = t.height
	}

	minGridX := minX / t.gridSize
	minGridY := minZ / t.gridSize
	maxGridX := maxX / t.gridSize
	maxGridY := maxZ / t.gridSize

	// 获取center为中心，半径范围radius内的所有格子
	towers := make([]*Tower, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt, err := t.getTowerByPos(gridX, gridY)
			if err == nil && tt != nil {
				towers = append(towers, tt)
			}
		}
	}

	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			pos := ii.GetPos().Mul(100)
			//pos.SubS(t.AnchorPos)
			offRadius := ii.GetModelRadius() + float32(radius)
			if IsNotCheckTargetRadius {
				offRadius -= ii.GetModelRadius()
			}
			temp := ncenter.Sub(pos)
			if temp.Sqr() < offRadius*offRadius {
				return cb(ii)
			}
			return false
		})
	}
}

// // 遍历center为中心，半径范围radius,角度为angle,朝向为rota的扇形内所有实体执行cb
// angle值是0到180，计算的时候，是左右各扇形多少度，超这个值会找不到对象
func (t *Tiles) TravsalSector(center *linmath.Vector3, radius int, rota int32, angle int32, cb func(iserver.ICoordEntity) bool, IsNotCheckTargetRadius bool) {
	ncenter := center.Mul(100)
	rawCenter := ncenter.Sub(t.AnchorPos)
	minX := int(rawCenter.X) - radius
	minZ := int(rawCenter.Z) - radius
	maxX := int(rawCenter.X) + radius
	maxZ := int(rawCenter.Z) + radius

	if minX < 0 {
		minX = 0
	}
	if minZ < 0 {
		minZ = 0
	}
	if maxX > t.width {
		maxX = t.width
	}
	if maxZ > t.height {
		maxZ = t.height
	}

	minGridX := minX / t.gridSize
	minGridY := minZ / t.gridSize
	maxGridX := maxX/t.gridSize + 1
	maxGridY := maxZ/t.gridSize + 1

	// 获取center为中心，半径范围radius内的所有格子
	towers := make([]*Tower, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt, err := t.getTowerByPos(gridX, gridY)
			if err == nil && tt != nil {
				towers = append(towers, tt)
			}
		}
	}

	// 朝向转化成向量值
	forward := linmath.Rota2Vector(rota)

	cosforward := math.Pi * float64(angle) / float64(180)
	// logger.Warn("计算扇形：cosforward->", cosforward, "angle->", angle)
	cosforward = math.Cos(cosforward)
	// fmt.Println("cosforward:", cosforward)
	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			pos := ii.GetPos().Mul(100)
			//pos.SubS(t.AnchorPos)
			temp := ncenter.Sub(pos)
			temp.Y = 0 //按平面算
			//判断当前点与中心点的距离是否小于半径
			offRadius := radius + int(ii.GetModelRadius())
			if IsNotCheckTargetRadius {
				offRadius -= int(ii.GetModelRadius())
			}
			if int(temp.Sqr()) < offRadius*offRadius {
				// if int(pos.X) >= minX && int(pos.X) <= maxX && int(pos.Z) >= minZ && int(pos.Z) <= maxZ {
				// 计算目标和玩家朝向间的夹角，与扇形角度比较
				checkForward := pos.Sub(ncenter)
				checkForward.Y = 0
				checkForward.Normalize()
				coscheck := float64(checkForward.Dot(forward))
				// fmt.Println("coscheck:", coscheck)
				if cosforward <= coscheck {
					return cb(ii)
				}
				// logger.Warn("计算扇形：cosforward->", cosforward)
				// logger.Warn("计算扇形：forward->", forward, "checkForward->", checkForward, "coscheck->", coscheck)
				// fAngle := math.Acos(float64(checkForward.Dot(forward))) * 180 / math.Pi //这里拿到的是角度

				// if fAngle <= float64(angle) {
				// 	return cb(ii)
				// }
			}
			return false
		})
	}
}

// 遍历center为中心，长宽为 length,width,朝向为rota的矩形内所有实体执行cb
func (t *Tiles) TravsalSquare(center *linmath.Vector3, length, width int, rota int32, cb func(iserver.ICoordEntity) bool, IsNotCheckTargetRadius bool) {
	ncenter := center.Mul(100)
	rawCenter := ncenter.Sub(t.AnchorPos)

	forward := linmath.Rota2Vector(rota + 90) //如果需要方块默认啊不旋转，那用90度来做
	// 获取偏移的矩形的4个点的坐标
	p1, p2, p3, p4 := linmath.GetSquare4PPos(rawCenter, length, width, forward) //float64(rota-90)/180*math.Pi)

	checkRadius := 0
	if length > width {
		checkRadius = length
	} else {
		checkRadius = width
	}
	minX := int(rawCenter.X) - checkRadius/2
	minZ := int(rawCenter.Z) - checkRadius/2
	maxX := int(rawCenter.X) + checkRadius/2
	maxZ := int(rawCenter.Z) + checkRadius/2

	if minX < 0 {
		minX = 0
	}
	if minZ < 0 {
		minZ = 0
	}
	if maxX > t.width {
		maxX = t.width
	}
	if maxZ > t.height {
		maxZ = t.height
	}

	minGridX := minX / t.gridSize
	minGridY := minZ / t.gridSize
	maxGridX := maxX / t.gridSize
	maxGridY := maxZ / t.gridSize

	// 获取center为中心，半径范围radius内的所有格子
	towers := make([]*Tower, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt, err := t.getTowerByPos(gridX, gridY)
			if err == nil && tt != nil {
				towers = append(towers, tt)
			}
		}
	}

	// // 朝向转化成向量值
	// forward := linmath.Rota2Vector(rota)
	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			r := ii.GetModelRadius()
			if IsNotCheckTargetRadius {
				r = 0
			}
			pos := ii.GetPos().Mul(100)
			pos.SubS(t.AnchorPos)
			pos.Y = 0
			// 计算目标是否在矩形范围内
			if r > 51 {
				if linmath.IsCircleInMatrix(p1, p2, p3, p4, pos, r) {
					return cb(ii)
				}
			}
			if linmath.IsPointInMatrix(p1, p2, p3, p4, pos) {
				return cb(ii)
			}

			return false
		})
	}
}

// 遍历center所在的Tower，在该Tower内的center为中心，半径范围radius内的所有实体执行cb
func (t *Tiles) TravsalCenter(center *linmath.Vector3, radius int, cb func(iserver.ICoordEntity) bool) {
	ncenter := center.Mul(100)
	rawCenter := ncenter.Sub(t.AnchorPos)
	// rawCenter.X = rawCenter.X - t.AnchorPos.X
	// rawCenter.Z = rawCenter.Z - t.AnchorPos.Z

	minX := int(rawCenter.X) - radius
	minZ := int(rawCenter.Z) - radius
	maxX := int(rawCenter.X) + radius
	maxZ := int(rawCenter.Z) + radius

	if minX < 0 {
		minX = 0
	}
	if minZ < 0 {
		minZ = 0
	}
	if maxX > t.width {
		maxX = t.width
	}
	if maxZ > t.height {
		maxZ = t.height
	}

	minGridX := minX / t.gridSize
	minGridY := minZ / t.gridSize
	maxGridX := maxX / t.gridSize
	maxGridY := maxZ / t.gridSize

	// 获取center为中心，半径范围radius内的所有格子
	towers := make([]*Tower, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt, err := t.getTowerByPos(gridX, gridY)
			if err == nil && tt != nil {
				towers = append(towers, tt)
			}
		}
	}

	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			pos := ii.GetPos().Mul(100)
			//pos.SubS(t.AnchorPos)
			offRadius := float32(radius)
			temp := ncenter.Sub(pos)
			if temp.Sqr() < offRadius*offRadius {
				return cb(ii)
			}
			return false
		})
	}
}

// 遍历center为中心，已radius为半径的圆去掉已innerRadius为圆的面积
func (t *Tiles) TravsalRing(center *linmath.Vector3, radius, innerradius int, cb func(iserver.ICoordEntity) bool) {
	ncenter := center.Mul(100)
	rawCenter := ncenter.Sub(t.AnchorPos)

	minX := int(rawCenter.X) - radius
	minZ := int(rawCenter.Z) - radius
	maxX := int(rawCenter.X) + radius
	maxZ := int(rawCenter.Z) + radius

	if minX < 0 {
		minX = 0
	}
	if minZ < 0 {
		minZ = 0
	}
	if maxX > t.width {
		maxX = t.width
	}
	if maxZ > t.height {
		maxZ = t.height
	}

	minGridX := minX / t.gridSize
	minGridY := minZ / t.gridSize
	maxGridX := maxX / t.gridSize
	maxGridY := maxZ / t.gridSize

	// 获取center为中心，半径范围radius内的所有格子
	towers := make([]*Tower, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt, err := t.getTowerByPos(gridX, gridY)
			if err == nil && tt != nil {
				towers = append(towers, tt)
			}
		}
	}

	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			pos := ii.GetPos().Mul(100)
			// pos.SubS(t.AnchorPos)
			temp := pos.Sub(ncenter)
			v := int(temp.Sqr())
			if innerradius*innerradius < v && v < radius*radius {
				return cb(ii)
			}
			return false
		})
	}
}

// 遍历center为中心，已radius为半径的圆去掉已innerRadius为圆的面积，选取朝向rota，角度为angle的扇环面积
func (t *Tiles) TravsalSectorRing(center *linmath.Vector3, radius, innerradius int, rota, angle int32, cb func(iserver.ICoordEntity) bool) {
	ncenter := center.Mul(100)
	rawCenter := ncenter.Sub(t.AnchorPos)

	minX := int(rawCenter.X) - radius
	minZ := int(rawCenter.Z) - radius
	maxX := int(rawCenter.X) + radius
	maxZ := int(rawCenter.Z) + radius

	if minX < 0 {
		minX = 0
	}
	if minZ < 0 {
		minZ = 0
	}
	if maxX > t.width {
		maxX = t.width
	}
	if maxZ > t.height {
		maxZ = t.height
	}

	minGridX := minX / t.gridSize
	minGridY := minZ / t.gridSize
	maxGridX := maxX / t.gridSize
	maxGridY := maxZ / t.gridSize

	// 获取center为中心，半径范围radius内的所有格子
	towers := make([]*Tower, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt, err := t.getTowerByPos(gridX, gridY)
			if err == nil && tt != nil {
				towers = append(towers, tt)
			}
		}
	}
	// 朝向转化成向量值
	forward := linmath.Rota2Vector(rota)
	cosforward := math.Pi / float64(180/angle)
	cosforward = math.Cos(cosforward)
	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			pos := ii.GetPos().Mul(100)
			// pos.SubS(t.AnchorPos)
			temp := pos.Sub(ncenter)
			temp.Y = 0
			v := int(temp.Sqr())
			//在环内
			if innerradius*innerradius < v && v < radius*radius {
				// 计算目标和玩家朝向间的夹角，与扇形角度比较
				// checkForward := pos.Sub(*center)
				// checkForward.Y = 0
				temp.Normalize()
				coscheck := float64(temp.Dot(forward))
				if cosforward <= coscheck {
					return cb(ii)
				}
				// fAngle := math.Acos(float64(checkForward.Dot(forward))) * 180 / math.Pi //这里拿到的是角度
				// if fAngle <= float64(angle) {
				// 	return cb(ii)
				// }
				// return cb(ii)
			}
			return false
		})
	}
}

func (t *Tiles) GetTowerIDInRect(rect *common.Rect) []int {

	rect.MinX = rect.MinX - int(t.AnchorPos.X)
	rect.MaxX = rect.MaxX - int(t.AnchorPos.X)
	rect.MinY = rect.MinY - int(t.AnchorPos.Y)
	rect.MaxY = rect.MaxY - int(t.AnchorPos.Y)

	if rect.MinX < 0 {
		rect.MinX = 0
	}
	if rect.MinY < 0 {
		rect.MinY = 0
	}
	if rect.MaxX > t.width {
		rect.MaxX = t.width
	}
	if rect.MaxY > t.height {
		rect.MaxY = t.height
	}

	minGridX := rect.MinX / t.gridSize
	minGridY := rect.MinY / t.gridSize
	maxGridX := rect.MaxX / t.gridSize
	maxGridY := rect.MaxY / t.gridSize

	if maxGridX*t.gridSize < rect.MaxX {
		maxGridX += 1
	}

	if maxGridY*t.gridSize < rect.MaxY {
		maxGridY += 1
	}

	// 获取center为中心，半径范围内的所有格子
	towerIDs := make([]int, 0)
	for gridX := minGridX; gridX <= maxGridX; gridX++ {
		for gridY := minGridY; gridY <= maxGridY; gridY++ {
			tt := t.getTowerID(gridX, gridY)
			if tt >= 0 {
				towerIDs = append(towerIDs, tt)
			}
		}
	}

	return towerIDs
}
func (t *Tiles) TraversalByIDList(rect *common.Rect, towerIDs []int, cb func(iserver.ICoordEntity) bool) {
	towers := make([]*Tower, 0)
	for _, id := range towerIDs {
		tt, err := t.getTowerByID(id)
		if err == nil && tt != nil {
			towers = append(towers, tt)
		}
	}

	// 遍历
	for _, tt := range towers {
		tt.TravsalAOINoCheck(func(ii iserver.ICoordEntity) bool {
			pos := ii.GetPos().Mul(100)
			pos.SubS(t.AnchorPos)
			if int(pos.X) >= rect.MinX && int(pos.X) <= rect.MaxX && int(pos.Z) >= rect.MinY && int(pos.Z) <= rect.MaxY {
				return cb(ii)
			}
			return false
		})
	}
}

/*
测试使用，检查地图遗漏的对象
*/
func (this *Tiles) TraverAll() {
	for _, v := range this.entites {
		logger.Debugf(logger.LogKey_Default, "%s", v.entity)
	}
	for _, t := range this.towers {
		for v := t.entities.Front(); v != nil; v = v.Next() {
			logger.Debugf(logger.LogKey_Default, "%s", v.Value)
		}
	}
}
